#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <stdlib.h>
#include <netinet/in.h>
#include <unistd.h>
#include <pthread.h>
#include <iostream>
#include <cstring>
#include "des.h"
using namespace std;

#define BUF_SIZE 1000

const char client_ID[] = "kha-zix";
const char K_client[] = "123455678";
const char K_client_TGS[] = "87654321";
const char K_TGS[] = "abcdefgh";
const char K_client_SS[] = "stuvwxyz";
const char K_SS[] = "hgfedcba";
int fd_for_client_to_AS[2];     //用于客户端向AS发送clientID的管道

int fd_for_AS_to_client_A[2];    //用于AS向客户端发送消息A的管道

int fd_for_AS_to_client_B[2];    //用户AS向客户端发送消息B的管道
                                //以下解释以此类推
int fd_for_client_to_TGS_C_serviceID[2];    

int fd_for_client_to_TGS_C_B[2];  

int fd_for_client_to_TGS_D[2];   

int fd_for_TGS_to_client_E_serviceID[2];   

int fd_for_TGS_to_client_E_ST[2];  

int fd_for_TGS_to_client_F[2];   

int fd_for_client_to_SS_E_serviceID[2];

int fd_for_client_to_SS_E_ST[2];

int fd_for_client_to_SS_G[2];

int fd_for_SS_to_client_H[2];

int mLenA, mLenB, mLenC, mLenD, mLenE, mLenF, mLenG, mLenH;
time_t timestamp1;
time_t timestamp2;

void AS_serve() {
    char recv_buffer[BUF_SIZE];
    const char error_buffer[] = "Invalid ID!";
    char TGT_plaintext[BUF_SIZE];
    char A[BUF_SIZE], B[BUF_SIZE];
    char A_send_buffer[BUF_SIZE], B_send_buffer[BUF_SIZE];

    memset(recv_buffer, 0, sizeof(recv_buffer));

    //当没有接收到客户端发来的信息时，查看管道，看是否有客户端发来的客户端ID
    //由于是同步问题，所以需要保证在消息出现时读取动作至少执行一次。

    puts("AS等待客户端发来请求...\n");

    read(fd_for_client_to_AS[0], recv_buffer, BUF_SIZE);
    
    puts("AS收到了来到了客户端的请求!\n");

    printf("AS收到的客户端ID为: %s\n\n", recv_buffer);

    //检验是否存在这样的客户ID
    if (strcmp(recv_buffer, client_ID) != 0) {

        //如果没有，那么向缓冲区输出错误消息
        write(fd_for_AS_to_client_A[1], error_buffer, sizeof(error_buffer));
        write(fd_for_AS_to_client_B[1], error_buffer, sizeof(error_buffer));
    }
    else {

        //如果有的话，利用DES加密算法加密对应的消息，发送给客户端
        //这里的encode,decode函数为第一次作业中DES加密算法所封装好的函数
        string A = des_encode(K_client, K_client_TGS);        

        cout << "AS将要发回的消息A为：" << A << "\n\n";

        write(fd_for_AS_to_client_A[1],  A.c_str(), BUF_SIZE);
        sprintf(TGT_plaintext, "<%s, %s, %d, %s>", client_ID, "127.0.0.1", 10000, K_client_TGS);

        cout << "AS将要发回的消息B明文为：" << TGT_plaintext << "\n\n";

        string B = des_encode(K_TGS, TGT_plaintext);

        cout << "AS将要发回的消息B密文为：" << B << "\n\n";
        write(fd_for_AS_to_client_B[1],  B.c_str(), BUF_SIZE);

        puts("AS向客户端发回了消息A和B!\n");
    }
}

void TGS_serve() {
    char service_ID_recv_buffer[BUF_SIZE], B_recv_buffer[BUF_SIZE];
    char service_ID[1000], ST_plaintext[1000];
    char ST[BUF_SIZE], F[BUF_SIZE], D_recv_buffer[BUF_SIZE];

    memset(service_ID_recv_buffer, 0, sizeof(service_ID_recv_buffer));
    memset(B_recv_buffer, 0, sizeof(B_recv_buffer));
    memset(D_recv_buffer, 0, sizeof(D_recv_buffer));

    puts("TGS等待客户端发来的消息C和D...\n");
    //不断从客户端接收客户端发来的消息C和D，当这三种消息全部收到时停止循环

    read(fd_for_client_to_TGS_C_serviceID[0], service_ID_recv_buffer,BUF_SIZE) ;
    read(fd_for_client_to_TGS_C_B[0], B_recv_buffer, BUF_SIZE);
    read(fd_for_client_to_TGS_D[0], D_recv_buffer, BUF_SIZE);
    
    puts("TGS收到了客户端发来的消息C和D!\n");

    sprintf(ST_plaintext, "<%s, %s, %d, %s>", client_ID, "127.0.0.1", 10000, K_client_SS);


    string ST_str = des_encode(K_SS, ST_plaintext);

    write(fd_for_TGS_to_client_E_serviceID[1], service_ID, BUF_SIZE);
    write(fd_for_TGS_to_client_E_ST[1], ST_str.c_str(), BUF_SIZE);

    string F_str = des_encode(K_client_TGS, K_client_SS);
    write(fd_for_TGS_to_client_F[1], F, BUF_SIZE);

    puts("TGS向客户端发回了消息E和F!\n");

}

void SS_serve() {
    char service_ID_recv_buffer[BUF_SIZE], ST_recv_buffer[BUF_SIZE], G_recv_buffer[BUF_SIZE]; 

    memset(service_ID_recv_buffer, 0, sizeof(service_ID_recv_buffer));
    memset(ST_recv_buffer, 0, sizeof(ST_recv_buffer));
    memset(G_recv_buffer, 0, sizeof(G_recv_buffer));

    read(fd_for_client_to_SS_E_serviceID[0], service_ID_recv_buffer, BUF_SIZE);
    read(fd_for_client_to_SS_E_ST[0], ST_recv_buffer, BUF_SIZE);
    read(fd_for_client_to_SS_G[0], G_recv_buffer, BUF_SIZE);

    string G_plain_text = des_decode(K_client_SS, G_recv_buffer);
    int lenG = G_plain_text.length();
    string G_timestamp;
    bool start_cut = false;

    cout << "解密得到的G明文: " << G_plain_text << endl << endl;


    for (int i = 0; i < lenG; i++) {
        if (G_plain_text[i] == '>') {
            break;
        }

        if (!start_cut && G_plain_text[i] == ',') {
            start_cut = true;
            continue;
        }

        if (start_cut) {
            G_timestamp += G_plain_text[i];
        }
    }

    cout << "提取出的时间戳为:" << G_timestamp << endl << endl;
    int get_timestamp = stoi(G_timestamp);

    char temp_H[BUF_SIZE];

    sprintf(temp_H, "<%s,%d>", client_ID, get_timestamp + 1);
    
    printf("SS将要发送给客户端的明文为：%s\n\n", temp_H);

    string H = des_encode(K_client_SS, temp_H);
    cout << "SS将要发送给客户端的密文为：" << H << "\n\n";
    write(fd_for_SS_to_client_H[1], H.c_str(), BUF_SIZE);

}

void create_pipes() {
    /*
    int pipe(fd[2]);
    函数传入值 fd[2]:管道的两个文件描述符，之后就是可以直接操作者两个文件描述符
    0用于读，1用于写，看上面函数调用时的例子即可明白
    */

    pipe(fd_for_client_to_AS);
    pipe(fd_for_AS_to_client_A);
    pipe(fd_for_AS_to_client_B);
    pipe(fd_for_client_to_TGS_C_serviceID);
    pipe(fd_for_client_to_TGS_C_B);
    pipe(fd_for_client_to_TGS_D);
    pipe(fd_for_TGS_to_client_E_serviceID);
    pipe(fd_for_TGS_to_client_E_ST);
    pipe(fd_for_TGS_to_client_F);
    pipe(fd_for_client_to_SS_E_serviceID);
    pipe(fd_for_client_to_SS_E_ST);
    pipe(fd_for_client_to_SS_G);
    pipe(fd_for_SS_to_client_H);

}

int main() {

    char A_recv_buffer[BUF_SIZE], B_recv_buffer[BUF_SIZE], ST_recv_buffer[BUF_SIZE], F_recv_buffer[BUF_SIZE], D_send_buffer[BUF_SIZE];
    char service_ID_recv_buffer[BUF_SIZE], G[BUF_SIZE];
    pid_t client_AS_pid, client_TGS_pid, client_SS_pid;
    int timestamp = 10;

    memset(A_recv_buffer, 0, sizeof(A_recv_buffer));
    memset(B_recv_buffer, 0, sizeof(B_recv_buffer));
    memset(ST_recv_buffer, 0, sizeof(ST_recv_buffer));
    memset(F_recv_buffer, 0, sizeof(F_recv_buffer));
    memset(service_ID_recv_buffer, 0, sizeof(service_ID_recv_buffer));

    create_pipes();

    client_AS_pid = fork();

    //如果是子进程，那么开始AS的服务，即AS一直等待客户端发来请求
    if (client_AS_pid == 0) {
        AS_serve();
        return 0;
    }

    write(fd_for_client_to_AS[1], "kha-zix", BUF_SIZE);    //向AS发起请求，这里是正确的ID

    //等待AS发来消息
    read(fd_for_AS_to_client_A[0], A_recv_buffer, BUF_SIZE);
    read(fd_for_AS_to_client_B[0], B_recv_buffer, BUF_SIZE);
    
    puts("客户端收到了AS发来的A和B!\n");
    //收到AS的消息，向TGS发送消息C，包括serviceID和从AS得到的消息B，和D
    
    printf("客户端收到AS发来的消息A为: %s\n\n", A_recv_buffer);
    printf("客户端收到AS发来的消息B为: %s\n\n", B_recv_buffer);

    char temp_D[BUF_SIZE];
    int temp_D_int[BUF_SIZE];

    client_TGS_pid = fork();

    if (client_TGS_pid == 0) {
        TGS_serve();
        return 0;
    }

    sprintf(temp_D, "<%s,%d>", client_ID, timestamp);

    printf("客户端将要发送给TGS的消息D明文是: %s\n\n", temp_D);

    string D = des_encode(K_client_TGS, temp_D);

    cout << "客户端将要发送给TGS的消息D密文是: " << D << "\n\n";

    write(fd_for_client_to_TGS_C_serviceID[1], "11111", BUF_SIZE);
    write(fd_for_client_to_TGS_C_B[1], B_recv_buffer, BUF_SIZE);
    write(fd_for_client_to_TGS_D[1], D.c_str(), BUF_SIZE);

    puts("客户端向TGS发送了消息C和D!\n");

    //等待TGS端返回的消息
    read(fd_for_TGS_to_client_E_serviceID[0], service_ID_recv_buffer, BUF_SIZE);
    read(fd_for_TGS_to_client_E_ST[0], ST_recv_buffer, BUF_SIZE);
    read(fd_for_TGS_to_client_F[0], F_recv_buffer, BUF_SIZE);

    puts("客户端接收到了TGS发来的E和F!");
    
    
    client_SS_pid = fork();

    if (client_SS_pid == 0) {
        SS_serve();
        return 0;
    }

    //客户端向SS发送消息E和G
    char temp_G[BUF_SIZE];
    sprintf(temp_G, "<%s,%d>", client_ID, timestamp);
    string G_str = des_encode(K_client_SS, temp_G);

    printf("客户端将要发送给SS的消息G明文是: %s\n\n", temp_G);

    cout << "客户端将要发送给SS的消息G密文是: " << G_str << "\n\n";

    write(fd_for_client_to_SS_E_serviceID[1], service_ID_recv_buffer, BUF_SIZE);
    write(fd_for_client_to_SS_E_ST[1], ST_recv_buffer, BUF_SIZE);
    write(fd_for_client_to_SS_G[1], G_str.c_str(), BUF_SIZE);

    char H_recv_buff[BUF_SIZE];

    read(fd_for_SS_to_client_H[0], H_recv_buff, BUF_SIZE);

    printf("客户端收到SS发来的密文为：%s\n\n", H_recv_buff);

    string H_plain_text = des_decode(K_client_SS, H_recv_buff);

    cout << "客户端解密得到的明文为：" << H_plain_text << "\n\n";

    int lenH = H_plain_text.length();
    string H_timestamp;
    bool start_cut = false;

    for (int i = 0; i < lenH; i++) {
        if (H_plain_text[i] == '>') {
            break;
        }

        if (!start_cut && H_plain_text[i] == ',') {
            start_cut = true;
            continue;
        }

        if (start_cut) {
            H_timestamp += H_plain_text[i];
        }
    }

    int get_timestamp = stoi(H_timestamp);

    cout << "提取到SS更新后的时间戳为：" << get_timestamp << "\n\n";

    if (get_timestamp == timestamp + 1) {
        puts("SS可以信赖!");
    }

    return 0;
}
